package org.beetl.sql.core.engine.template;


import org.beetl.core.Configuration;
import org.beetl.core.Template;
import org.beetl.core.exception.BeetlException;
import org.beetl.core.exception.ErrorInfo;
import org.beetl.core.resource.StringTemplateResourceLoader;
import org.beetl.sql.clazz.kit.AutoSQLEnum;
import org.beetl.sql.core.SqlId;
import org.beetl.sql.core.concat.ConcatBuilder;
import org.beetl.sql.core.db.DBStyle;
import org.beetl.sql.core.engine.StringSqlTemplateLoader;
import org.beetl.sql.core.loader.SQLLoader;

import java.util.Map;
import java.util.Properties;

/**
 * beetl模板引擎实现
 */
public class BeetlTemplateEngine implements SQLTemplateEngine {

    Beetl beetl = null;

    StringTemplateResourceLoader tempLoader = new StringTemplateResourceLoader();


    public String STATEMENT_START;// 定界符开始符号
    public String STATEMENT_END;// 定界符结束符号
    public String HOLDER_START;// 占位符开始符号
    public String HOLDER_END;// 占位符结束符号

    @Override
    public void init(SQLLoader loader, Properties ps) {
        beetl = new Beetl(loader, ps);

        Configuration cf = beetl.getGroupTemplate().getConf();
        STATEMENT_START = cf.getStatementStart();
        STATEMENT_END = cf.getStatementEnd();
        if (STATEMENT_END == null || STATEMENT_END.length() == 0) {
            STATEMENT_END = System.getProperty("line.separator", "\n");
        }
        HOLDER_START = cf.getPlaceholderStart();
        HOLDER_END = cf.getPlaceholderEnd();
    }

	@Override
	public void customizedSQLLoader(SQLLoader loader) {
		StringSqlTemplateLoader stringSqlTemplateLoader = new StringSqlTemplateLoader(loader);
		beetl.getGroupTemplate().setResourceLoader(stringSqlTemplateLoader);
	}

	@Override
    public SQLTemplate getSqlTemplate(SqlId id) {
        Template template = beetl.getGroupTemplate().getTemplate(id);
        return new BeetlSQLTemplate(template);
    }

    @Override
    public SQLTemplate getSqlTemplate(SqlId id, TemplateContext parent) {
        BeetlTemplateContext context = (BeetlTemplateContext) parent;
        Template template = beetl.getGroupTemplate().getTemplate(id, context.ctx);
        return new BeetlSQLTemplate(template);
    }

	@Override
	public String runTemplate(String template, Map paras) {
		Template beetlTemplate = beetl.getGroupTemplate().getTemplate(template,tempLoader);
		if(paras!=null){
			beetlTemplate.binding(paras);
		}
		//TODO,如何打印出错误
		String str = beetlTemplate.render();
		return str;

	}


	@Override
    public SQLErrorInfo validate(String sqlTemplate) {
        StringTemplateResourceLoader templateResourceLoader = new StringTemplateResourceLoader();
        BeetlException exception = this.beetl.getGroupTemplate().validateTemplate(sqlTemplate, templateResourceLoader);
        if (exception == null) {
            //没有问题的模板
            return null;
        }
        /**
         * 注意，错误行数提示没有纠正到相对于markdown文件位置，而是模板本生位置,如果想得到相对于模板文件位置的错误行数
         * 参考
         * BeetlSQLTemplateExceptionHandler
         */
        ErrorInfo error = new ErrorInfo(exception);
        SQLErrorInfo sqlErrorInfo = new SQLErrorInfo();
        sqlErrorInfo.setLine(error.getErrorTokenLine());
        sqlErrorInfo.setToken(error.getErrorTokenText());
        sqlErrorInfo.setRoot(error.getCause());
        return sqlErrorInfo;
    }

    @Override
    public void genVar(ConcatBuilder concatBuilder, String var) {
        appendVar(concatBuilder, var);
    }



	@Override
    public String appendVar(String express) {
        return HOLDER_START + express + HOLDER_END + " ";
    }

    @Override
    public void genTrimStart(ConcatBuilder concatBuilder) {
		genTrimStart(concatBuilder, ",");
    }

	@Override
	public void genTrimStart(ConcatBuilder concatBuilder, String keyword) {
		appendStatement(concatBuilder, "trim({prefixOverrides:'"+keyword+"'}){");
	}

	@Override
    public void genTrimEnd(ConcatBuilder concatBuilder) {
        appendStatement(concatBuilder, "}");
    }

    @Override
    public void genIfNotEmptyStart(ConcatBuilder concatBuilder, String var) {
        appendStatement(concatBuilder, "if(isNotEmpty(" + var + ")){");
    }

    @Override
    public void genIfNotEmptyEnd(ConcatBuilder concatBuilder) {
        appendStatement(concatBuilder, "}");
    }

	@Override
	public void genForStart(ConcatBuilder concatBuilder, String collection, String var) {
    	String express = "for("+var+" in "+collection+"){";
		appendStatement(concatBuilder, express);
	}

	@Override
	public void genForEnd(ConcatBuilder concatBuilder) {
		appendStatement(concatBuilder, "}");
	}

	@Override
    public void genTestVar(ConcatBuilder concatBuilder, String var) {
        appendVar(concatBuilder, "db.testNull(" + var + "!,\"" + var + "\")");
    }

	/**
	 *
	 * @param concatBuilder
	 * @param var
	 * @param realVa
	 * @see org.beetl.sql.annotation.builder.AttributeConvert#toAutoSqlPart(DBStyle, AutoSQLEnum, String)
	 */
	@Override
	public void genTestRealVar(ConcatBuilder concatBuilder, String var, String realVa) {
		String newHolder = realVa.replace("$$","?");
		appendVar(concatBuilder, "db.testNull(" + var + "!,\"" + var + "\",\""+newHolder+"\")");
	}

	@Override
    public void genTestVar(ConcatBuilder concatBuilder, String var, String col) {

        if (col.startsWith("'")) {
            appendVar(concatBuilder, "db.testColNull(" + var + ",\"" + col + "\")");
        } else {
        	String colName = concatBuilder.getCtx().getKeyWordHandler().getCol(col);
            appendVar(concatBuilder, "db.testColNull(" + var + ",'" + colName + "')");
        }
    }
	@Override
	public
	void genTestVarOrDefault(ConcatBuilder concatBuilder,String var,String defaultValue){

    	appendVar(concatBuilder, "db.testVarNull(" + var + ",\"" + defaultValue + "\")");

	}

    @Override
    public String wrapString(String str) {
        if (str.startsWith(STATEMENT_START)) {
            return "\\" + str;
        } else {
            return str;
        }
    }

    protected void appendVar(ConcatBuilder concatBuilder, String express) {
        concatBuilder.append(HOLDER_START).append(express).append(HOLDER_END).append(" ");
    }

    protected void appendStatement(ConcatBuilder concatBuilder, String statement) {
        concatBuilder.append(STATEMENT_START).append(statement).append(STATEMENT_END);
    }

    public Beetl getBeetl() {
        return beetl;
    }

    @Override
    public void clear(){
        this.getBeetl().getGroupTemplate().getProgramCache().clearAll();
    }
}
